package com.lawson.survivor;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.CountDownTimer;

public class LocationFinder extends CountDownTimer implements LocationListener, LocationFindListener {
	boolean locationCountdownFinished = false;
	boolean locationCountdownInProgress = false; 
	private LocationManager locationManager;
	private LocationFindListener onLocationFoundListener;
	private Location location;	
	private Context context;
	private long minDistance;

	public Context getContext() {
		return context;
	}

	public LocationFinder(Context context, long millisInFuture, long countDownInterval, long minDistance) {
		super(millisInFuture, countDownInterval);
		this.context = context;
		this.minDistance = minDistance;
		locationManager  = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, minDistance, this);
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, minDistance, this);
		
		//Start causes a timer to countdown waiting for a location fix.
		this.start();
	}

	public boolean isLocationCountdownFinished() {
		return locationCountdownFinished;
	}

	public boolean isLocationCountdownStarted() {
		return locationCountdownInProgress;
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		locationManager.removeUpdates(this);
	}

	@Override
	public void onTick(long millisUntilFinished) {
		if (!locationCountdownInProgress){
			locationCountdownInProgress = true;
			
			//Attempt to find recent location with accuracy on 'first tick'.
			List<String> providers = locationManager.getAllProviders();
			List<Location> recentLocations = new ArrayList<Location>();
			
			for(String provider:providers){
				Location location = locationManager.getLastKnownLocation(provider);
				
				if(location != null && location.getAccuracy() <= minDistance && (System.currentTimeMillis() - location.getTime()) <= 10000)
					recentLocations.add(location);	
			}
			
			if (!recentLocations.isEmpty()){
				location = recentLocations.get(0);
				onFinish();
			}
		}
	}

	@Override
	public void onFinish() {
		locationCountdownFinished = true;
		locationCountdownInProgress = false;
		locationManager.removeUpdates(this);
		onLocationFound(this.location);
	}

	@Override
	public void onLocationChanged(Location location) {
		if (location.getProvider().equals(LocationManager.GPS_PROVIDER)){
			this.location = location;
			onFinish();
		} else {
			this.location = location;
		}
	}

	@Override
	public void onProviderDisabled(String provider) {}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {}

	@Override
	public void onLocationFound(Location location) {
		if(onLocationFoundListener != null){
			onLocationFoundListener.onLocationFound(location);
		}
	}

	@Override
	public void onProviderEnabled(String provider) {}

	public LocationFindListener getOnLocationFoundListener() {
		return onLocationFoundListener;
	}

	public void setOnLocationFoundListener(LocationFindListener onLocationFoundListener) {
		this.onLocationFoundListener = onLocationFoundListener;
	}

	Comparator<? super Location> locationComparator = new Comparator<Location>(){

		@Override
		public int compare(Location lhs, Location rhs) {
			if (lhs == null && rhs == null){
				//equal
				return 0;
			}

			if(lhs == null && rhs != null){
				//favour rhs
				return -1;
			}

			if(lhs != null && rhs == null){
				//favour lhs
				return 1;
			}

			//boolean isFromSameProvider = isSameProvider(lhs.getProvider(),rhs.getProvider());

			// Check whether the new location fix is more or less accurate
			boolean isLhsMoreAccurate = lhs.getAccuracy() < rhs.getAccuracy();
			//boolean isLhsMoreRecent = lhs.getTime() > rhs.getTime();

			// Determine location quality using a combination of timeliness and accuracy
			if (isLhsMoreAccurate) {
				return 1;
			} else{
				return -1;
			}
		}
	};

}